﻿// -----------------------------------------------------------------------------------------------
//  <copyright file="TfsProjectTest.cs" company="http://buginbox.wordpress.com/">
//    Copyright (c) GNU General Public License version 2 (GPLv2)
//  </copyright>
// -----------------------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;

using Microsoft.TeamFoundation.TestManagement.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace TestPlanMigration
{
    /// <summary>
    /// The tfs project test.
    /// </summary>
    public class TfsProjectTest
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TfsProjectTest"/> class. Prevents a default instance of the <see cref="TfsProjectTest"/> class from being created.
        /// </summary>
        /// <param name="configuration">
        /// The configuration. 
        /// </param>
        /// <param name="project">
        /// The project. 
        /// </param>
        /// <param name="testProject">
        /// The test project. 
        /// </param>
        private TfsProjectTest(TfsConfig configuration, Project project, ITestManagementTeamProject testProject)
        {
            Configuration = configuration;
            Project = project;
            TestProject = testProject;
            LoadTestPlans(TestProject);
        }

        /// <summary>
        /// Gets the configuration.
        /// </summary>
        /// <value>
        /// The configuration. 
        /// </value>
        public TfsConfig Configuration { get; private set; }

        /// <summary>
        /// Gets the project.
        /// </summary>
        public Project Project { get; private set; }

        /// <summary>
        /// Gets the work item store.
        /// </summary>
        /// <value>
        /// The work item store. 
        /// </value>
        public ITestManagementTeamProject TestProject { get; private set; }

        /// <summary>
        /// Gets all the plans.
        /// </summary>
        public ITestPlanCollection AllPlans { get; private set; }

        /// <summary>
        /// Gets all the suites.
        /// </summary>
        public ITestSuiteCollection AllSuites { get; private set; }

        /// <summary>
        /// Gets all the test cases WI.
        /// </summary>
        public List<ITestCase> AllTestCases { get; private set; }

        /// <summary>
        /// The iterations
        /// </summary>
        private List<string> _iterations;

        /// <summary>
        /// Gets the iterations.
        /// </summary>
        public List<string> Iterations
        {
            get
            {
                return _iterations ?? (_iterations = GetNodes(Project.IterationRootNodes));
            }
        }

        /// <summary>
        /// The areas
        /// </summary>
        private List<string> _areas;

        /// <summary>
        /// Gets the areas.
        /// </summary>
        public List<string> Areas
        {
            get
            {
                return _areas ?? (_areas = GetNodes(Project.AreaRootNodes));
            }
        }

        /// <summary>
        /// News the configuration.
        /// </summary>
        /// <param name="configuration">
        /// The configuration. 
        /// </param>
        /// <param name="project">
        /// The project. 
        /// </param>
        /// <returns>
        /// </returns>
        public static TfsProjectTest NewTestProject(TfsConfig configuration, Project project)
        {
            if (configuration == null || project == null)
            {
                return null;
            }

            ITestManagementTeamProject testProject = configuration.TestService.GetTeamProject(project.Name);
            return new TfsProjectTest(configuration, project, testProject);
        }

        /// <summary>
        /// Loads the test plans.
        /// </summary>
        /// <param name="testProject">
        /// The test project. 
        /// </param>
        private void LoadTestPlans(ITestManagementTeamProject testProject)
        {
            var plans = testProject.TestPlans.Query("SELECT * FROM TestPlan");

            if (plans != null)
            {
                AllPlans = plans;

                var suites = testProject.TestSuites.Query("SELECT * FROM TestSuite");

                if (suites != null)
                {
                    AllSuites = suites;
                }
            }

            var testCases = testProject.TestCases.Query("SELECT * FROM WorkItems");

            AllTestCases = new List<ITestCase>();

            foreach (ITestCase testCase in testCases)
            {
                AllTestCases.Add(testCase);
            }
        }

        /// <summary>
        /// Gets the node values.
        /// </summary>
        /// <param name="nodes">
        /// The nodes. 
        /// </param>
        /// <returns>
        /// </returns>
        private static List<string> GetNodes(NodeCollection nodes)
        {
            var nodeValues = new List<string>();

            foreach (Node node in nodes)
            {
                GetNodes(node, nodeValues);
            }

            return nodeValues;
        }

        /// <summary>
        /// Gets the node values.
        /// </summary>
        /// <param name="node">
        /// The node. 
        /// </param>
        /// <param name="nodeValues">
        /// The node values. 
        /// </param>
        private static void GetNodes(Node node, List<string> nodeValues)
        {
            nodeValues.Add(node.Path);

            if (!node.HasChildNodes)
            {
                return;
            }

            foreach (Node subNode in node.ChildNodes)
            {
                GetNodes(subNode, nodeValues);
            }
        }

        /// <summary>
        /// Gets the or clone plan.
        /// </summary>
        /// <param name="destinationTestProject">
        /// The destination test project. 
        /// </param>
        /// <param name="planToClone">
        /// The plan to clone. 
        /// </param>
        /// <param name="prefix">
        /// The prefix. 
        /// </param>
        /// <returns>
        /// </returns>
        public static ITestPlan GetOrClonePlan(
            TfsProjectTest destinationTestProject, ITestPlan planToClone, string prefix)
        {
            ITestPlanCollection plans = destinationTestProject.AllPlans;

            if (plans == null)
            {
                return ClonePlan(destinationTestProject, planToClone, prefix);
            }

            var plan = plans.FirstOrDefault(x => x.Name == (prefix + planToClone.Name));

            if (plan == null)
            {
                return ClonePlan(destinationTestProject, planToClone, prefix);
            }

            return plan;
        }

        /// <summary>
        /// Clones the plan.
        /// </summary>
        /// <param name="destinationTestProject">
        /// The destination test project. 
        /// </param>
        /// <param name="planToClone">
        /// The plan to clone. 
        /// </param>
        /// <param name="prefix">
        /// The prefix. 
        /// </param>
        /// <returns>
        /// </returns>
        public static ITestPlan ClonePlan(TfsProjectTest destinationTestProject, ITestPlan planToClone, string prefix)
        {
            ITestPlan clonedPlan = destinationTestProject.TestProject.TestPlans.Create();

            clonedPlan.Name = prefix + planToClone.Name;

            // CopyUniquePlanName(planToClone.Name, destinationTestProject.AllPlans);
            clonedPlan.StartDate = planToClone.StartDate;
            clonedPlan.EndDate = planToClone.EndDate;

            if (!string.IsNullOrEmpty(planToClone.Iteration)
                && destinationTestProject.Iterations.Contains(planToClone.Iteration))
            {
                clonedPlan.Iteration = planToClone.Iteration;
            }

            if (!string.IsNullOrEmpty(planToClone.AreaPath)
                && destinationTestProject.Areas.Contains(planToClone.AreaPath))
            {
                clonedPlan.AreaPath = planToClone.AreaPath;
            }

            clonedPlan.Description = planToClone.Description;

            clonedPlan.AutomatedTestEnvironmentId = planToClone.AutomatedTestEnvironmentId;
            clonedPlan.AutomatedTestSettingsId = planToClone.AutomatedTestSettingsId;
            clonedPlan.ManualTestEnvironmentId = planToClone.ManualTestEnvironmentId;
            clonedPlan.ManualTestSettingsId = planToClone.ManualTestSettingsId;

            if (clonedPlan.Project == null)
            {
                return null;
            }

            clonedPlan.Save();

            return clonedPlan;
        }

        /// <summary>
        /// Copies the suite info.
        /// </summary>
        /// <param name="sourceSuiteToCopy">
        /// The source suite to copy. 
        /// </param>
        /// <param name="isRoot">
        /// if set to <c>true</c> [is root]. 
        /// </param>
        /// <param name="targetSuite">
        /// The target suite. 
        /// </param>
        /// <param name="destinationTestProject">
        /// The destination test project. 
        /// </param>
        public static void CopySuiteInfo(
            IStaticTestSuite sourceSuiteToCopy, 
            bool isRoot, 
            IStaticTestSuite targetSuite, 
            TfsProjectTest destinationTestProject)
        {
            if (!isRoot)
            {
                targetSuite.Title = sourceSuiteToCopy.Title;

                // CopyUniqueSuiteTitle(sourceSuiteToCopy.Title, destinationTestProject.AllSuites);
            }

            targetSuite.Description = sourceSuiteToCopy.Description;
        }

        /// <summary>
        /// Clones the suite.
        /// </summary>
        /// <param name="destinationTestProject">
        /// The destination test project. 
        /// </param>
        /// <param name="suiteToClone">
        /// The suite to clone. 
        /// </param>
        /// <returns>
        /// </returns>
        public static IStaticTestSuite CloneSuite(TfsProjectTest destinationTestProject, IStaticTestSuite suiteToClone)
        {
            IStaticTestSuite clonedSuite = destinationTestProject.TestProject.TestSuites.CreateStatic();

            CopySuiteInfo(suiteToClone, false, clonedSuite, destinationTestProject);

            return clonedSuite;
        }

        /////// <summary>
        /////// Copies the name
        /////// </summary>
        /////// <param name="originalName">Name of the original.</param>
        /////// <param name="targetPlans">The target plans.</param>
        /////// <returns></returns>
        ////private static string CopyUniquePlanName(string originalName, IEnumerable<ITestPlan> targetPlans)
        ////{
        ////    if (targetPlans != null && targetPlans.Any(x => x.Name == originalName))
        ////    {
        ////        return string.Format("{0} {1}", originalName, string.Format("({0})", Guid.NewGuid()));
        ////    }

        ////    return originalName;
        ////}

        /////// <summary>
        /////// Copies the name
        /////// </summary>
        /////// <param name="originalTitle">The original title.</param>
        /////// <param name="targetSuites">The target suites.</param>
        /////// <returns></returns>
        ////private static string CopyUniqueSuiteTitle(string originalTitle, IEnumerable<ITestSuiteBase> targetSuites)
        ////{
        ////    if (targetSuites != null && targetSuites.Any(x => x.Title == originalTitle))
        ////    {
        ////        return string.Format("{0} {1}", originalTitle, string.Format("(Clone - {0})", Guid.NewGuid()));
        ////    }

        ////    return originalTitle;
        ////}
    }
}